//----------------------------------------------------------------------------
// M A R I T I M E  R E S E A R C H  I N S T I T U T E  N E T H E R L A N D S
//----------------------------------------------------------------------------
// Copyright (C) 2008 - MARIN - All rights reserved - http://www.marin.nl
//----------------------------------------------------------------------------
// Program    : mermaid
// Module     : vbm
// File       : IncomingWaves.h
//----------------------------------------------------------------------------

#ifndef INCOMINGWAVES_H
#define INCOMINGWAVES_H

template <class T> class Array1D;

#include "defines.h"
#include "InteractiveWaves.h"
#include "Array2D.h"

#ifdef USE_CUDAINCOMINGWAVES
#include "CudaIncomingWaves.h"
class CudaIncomingWaves;
#endif

/// handles incoming waves in Gert Klopman's wave model
class IncomingWaves
{
public:

    IncomingWaves(int Nx1,
                  int Nx2,
                  REAL dx1,
                  REAL dx2,
                  const Array2D<REAL> &h0,
                  const Array2D<REAL> &U1,
                  const Array2D<REAL> &U2,
                  const Array2D<SHORT> &wet,
                  const Array2D<REAL> &kappa,
                  const Array2D<REAL> &vD0,
                  const Array2D<REAL> &vM0,
                  const Array2D<REAL> &vN0,
                  int wvin_spec_count,
                  const Array1D<REAL> &wvin_spec_ampl,
                  const Array1D<REAL> &wvin_spec_phase,
                  const Array1D<REAL> &wvin_spec_freq,
                  const Array1D<REAL> &wvin_spec_dir,
                  REAL g,
                  VariationalModel varmod);

    virtual ~IncomingWaves();

    void startup(REAL t, bool maxDepth, Array2D<REAL>* pZeta, Array2D<REAL>* pPhi);

    void compute(REAL t, REAL pslow,
                 Array1D<REAL> &zeta_in_N_ext, Array1D<REAL> &phi_in_N_ext, Array1D<REAL> &psi_in_N_ext,
                 Array1D<REAL> &zeta_in_N_cen, Array1D<REAL> &phi_in_N_cen, Array1D<REAL> &psi_in_N_cen,
                 Array1D<REAL> &zeta_in_N_int, Array1D<REAL> &phi_in_N_int, Array1D<REAL> &psi_in_N_int,
                 Array1D<REAL> &zeta_in_E_ext, Array1D<REAL> &phi_in_E_ext, Array1D<REAL> &psi_in_E_ext,
                 Array1D<REAL> &zeta_in_E_cen, Array1D<REAL> &phi_in_E_cen, Array1D<REAL> &psi_in_E_cen,
                 Array1D<REAL> &zeta_in_E_int, Array1D<REAL> &phi_in_E_int, Array1D<REAL> &psi_in_E_int,
                 Array1D<REAL> &zeta_in_S_ext, Array1D<REAL> &phi_in_S_ext, Array1D<REAL> &psi_in_S_ext,
                 Array1D<REAL> &zeta_in_S_cen, Array1D<REAL> &phi_in_S_cen, Array1D<REAL> &psi_in_S_cen,
                 Array1D<REAL> &zeta_in_S_int, Array1D<REAL> &phi_in_S_int, Array1D<REAL> &psi_in_S_int,
                 Array1D<REAL> &zeta_in_W_ext, Array1D<REAL> &phi_in_W_ext, Array1D<REAL> &psi_in_W_ext,
                 Array1D<REAL> &zeta_in_W_cen, Array1D<REAL> &phi_in_W_cen, Array1D<REAL> &psi_in_W_cen,
                 Array1D<REAL> &zeta_in_W_int, Array1D<REAL> &phi_in_W_int, Array1D<REAL> &psi_in_W_int);

private:

    /// @cond nevercall
    // should never be called !
    IncomingWaves();
    IncomingWaves(const IncomingWaves& m);
    IncomingWaves & operator=(const IncomingWaves& m);
    /// @endcond

    void initialize(const Array2D<REAL> &vM0);

    void wvin_init(int i1,
                   int i2,
                   int wv,
                   const Array2D<REAL> &vM0,
                   REAL *pwvin_W_ext_ampl,
                   REAL *pwvin_W_ext_phase,
                   REAL *pwvin_W_ext_freq,
                   REAL *pwvin_W_ext_facphi,
                   REAL *pwvin_W_ext_facpsi);

    void wvin_comp(int Nx2,
                   const Array1D<int> &wvin_W_count,
                   REAL t,
                   REAL pslow,
                   Array1D<REAL> &zeta_in_W_ext,
                   Array1D<REAL> &phi_in_W_ext,
                   Array1D<REAL> &psi_in_W_ext,
                   const Array2D<REAL> &wvin_W_ext_ampl,
                   const Array2D<REAL> &wvin_W_ext_phase,
                   const Array2D<REAL> &wvin_W_ext_freq,
                   const Array2D<REAL> &wvin_W_ext_facphi,
                   const Array2D<REAL> &wvin_W_ext_facpsi);

    void vbm_disper(REAL *pk,
                    REAL omega,
                    REAL h,
                    REAL U,
                    REAL kappa);

    int m_Nx1; ///< horizontal number of points
    int m_Nx2; ///< vertical number of points
    REAL m_dx1; ///< horizontal grid spacing (m)
    REAL m_dx2; ///< vertical grid spacing (m)
    REAL m_g; ///< gravitational constant
    VariationalModel m_varmod; ///< model to use
    const Array2D<REAL> &m_h0; ///< ref to depth table
    const Array2D<REAL> &m_U1; ///< ref to horizontal flow table
    const Array2D<REAL> &m_U2; ///< ref to vertical flow table
    const Array2D<SHORT> &m_wet; ///< ref to wet table
    const Array2D<REAL> &m_kappa; ///<
    const Array2D<REAL> &m_vD0; ///<
    const Array2D<REAL> &m_vN0; ///<
    int m_wvin_spec_count; ///<
    const Array1D<REAL> &m_wvin_spec_ampl; ///<
    const Array1D<REAL> &m_wvin_spec_phase; ///<
    const Array1D<REAL> &m_wvin_spec_freq; ///<
    const Array1D<REAL> &m_wvin_spec_dir; ///<
    Array1D<int> m_wvin_N_count; ///<
    Array1D<int> m_wvin_S_count; ///<
    Array1D<int> m_wvin_E_count; ///<
    Array1D<int> m_wvin_W_count; ///<
    Array2D<REAL> m_wvin_N_cen_phase; ///<
    Array2D<REAL> m_wvin_S_cen_phase; ///<
    Array2D<REAL> m_wvin_N_int_phase; ///<
    Array2D<REAL> m_wvin_S_int_phase; ///<
    Array2D<REAL> m_wvin_N_ext_phase; ///<
    Array2D<REAL> m_wvin_S_ext_phase; ///<
    Array2D<REAL> m_wvin_N_cen_facphi; ///<
    Array2D<REAL> m_wvin_S_cen_facphi; ///<
    Array2D<REAL> m_wvin_N_cen_facpsi; ///<
    Array2D<REAL> m_wvin_S_cen_facpsi; ///<
    Array2D<REAL> m_wvin_N_int_facphi; ///<
    Array2D<REAL> m_wvin_S_int_facphi; ///<
    Array2D<REAL> m_wvin_N_ext_facphi; ///<
    Array2D<REAL> m_wvin_S_ext_facphi; ///<
    Array2D<REAL> m_wvin_N_int_facpsi; ///<
    Array2D<REAL> m_wvin_S_int_facpsi; ///<
    Array2D<REAL> m_wvin_N_ext_facpsi; ///<
    Array2D<REAL> m_wvin_S_ext_facpsi; ///<
    Array2D<REAL> m_wvin_N_cen_ampl; ///<
    Array2D<REAL> m_wvin_N_cen_freq; ///<
    Array2D<REAL> m_wvin_S_cen_ampl; ///<
    Array2D<REAL> m_wvin_S_cen_freq; ///<
    Array2D<REAL> m_wvin_N_int_ampl; ///<
    Array2D<REAL> m_wvin_N_int_freq; ///<
    Array2D<REAL> m_wvin_S_int_ampl; ///<
    Array2D<REAL> m_wvin_N_ext_ampl; ///<
    Array2D<REAL> m_wvin_N_ext_freq; ///<
    Array2D<REAL> m_wvin_S_ext_ampl; ///<
    Array2D<REAL> m_wvin_S_int_freq; ///<
    Array2D<REAL> m_wvin_S_ext_freq; ///<
    Array2D<REAL> m_wvin_E_cen_phase; ///<
    Array2D<REAL> m_wvin_W_cen_phase; ///<
    Array2D<REAL> m_wvin_E_int_phase; ///<
    Array2D<REAL> m_wvin_E_ext_phase; ///<
    Array2D<REAL> m_wvin_W_int_phase; ///<
    Array2D<REAL> m_wvin_W_ext_phase; ///<
    Array2D<REAL> m_wvin_E_cen_facphi; ///<
    Array2D<REAL> m_wvin_E_cen_facpsi; ///<
    Array2D<REAL> m_wvin_W_cen_facphi; ///<
    Array2D<REAL> m_wvin_E_int_facphi; ///<
    Array2D<REAL> m_wvin_E_ext_facphi; ///<
    Array2D<REAL> m_wvin_W_cen_facpsi; ///<
    Array2D<REAL> m_wvin_E_int_facpsi; ///<
    Array2D<REAL> m_wvin_W_int_facphi; ///<
    Array2D<REAL> m_wvin_E_ext_facpsi; ///<
    Array2D<REAL> m_wvin_W_ext_facphi; ///<
    Array2D<REAL> m_wvin_W_int_facpsi; ///<
    Array2D<REAL> m_wvin_W_ext_facpsi; ///<
    Array2D<REAL> m_wvin_E_cen_ampl; ///<
    Array2D<REAL> m_wvin_E_cen_freq; ///<
    Array2D<REAL> m_wvin_W_cen_ampl; ///<
    Array2D<REAL> m_wvin_E_int_ampl; ///<
    Array2D<REAL> m_wvin_W_cen_freq; ///<
    Array2D<REAL> m_wvin_E_int_freq; ///<
    Array2D<REAL> m_wvin_E_ext_ampl; ///<
    Array2D<REAL> m_wvin_E_ext_freq; ///<
    Array2D<REAL> m_wvin_W_int_ampl; ///<
    Array2D<REAL> m_wvin_W_int_freq; ///<
    Array2D<REAL> m_wvin_W_ext_ampl; ///<
    Array2D<REAL> m_wvin_W_ext_freq; ///<
#ifdef USE_CUDAINCOMINGWAVES
    CudaIncomingWaves *m_pCudaIncomingWaves;
#endif

};

#endif // INCOMINGWAVES_H
